import re
import random
from proxy import Proxy
from database import Database

class ProxyGroup:
	def __init__(self, proxygroup_id):
		self.db = Database()
		self.id = proxygroup_id
		self._test_value_regexp = re.compile("(?P<property>[a-zA-Z0-9\-\_]+)(?P<operator>\>|\>=|=|!=|\<\>|\<=|\<)(?P<value>(\'|\")?[a-zA-Z0-9\.\-\_\@]+(\'|\")?)")

		# Get proxy group type
		sql = "SELECT type, proxy_group.order FROM proxy_group WHERE idproxy_group = '" + str(self.id) + "'"
		res = self.db.execute(sql)
		res = res[0]
		self.type  = res['type']
		self.order = res['order']

		# Get order value 
		if self.order == "major_order_value" or self.order == "minor_order_value":
			sql = "SELECT value " + \
				"FROM proxy_group_members " + \
				"INNER JOIN properties ON proxy_group_members.idc_property=properties.idproperty " + \
				"WHERE proxy_group_members.idc_proxy_group = '" + str(self.id) + "' " + \
				"AND properties.property = 'ORDER_VALUE'"
			res = self.db.execute(sql)
			self.order_value = res[0]
		else:
			self.order_value = "latency"

		# Get proxy group members
		sql = "SELECT * FROM proxy_group_members " + \
			"INNER JOIN properties ON proxy_group_members.idc_property = properties.idproperty " + \
			"WHERE proxy_group_members.idc_proxy_group = '" + str(self.id) + "' " + \
			"ORDER BY proxy_group_members.group_order"
		res = self.db.execute(sql)
		self.members = []
		for member in res:
			m = ( member['property'], member['value'] )
			self.members.append(m)

		self.proxys = self.load_matching_proxys()
		self.last_selected = ""

	def load_matching_proxys(self):
		position = 0
		max_position = self.members.__len__()	
		if position == max_position:
			# No search criteria, ALL active proxys selected
			sql = "SELECT idproxy FROM proxys WHERE checked IS NOT NULL and active=1"
			res = self.db.execute(sql)
			proxys = []
			for proxyid in res:
				proxys.append(Proxy(proxyid['idproxy']))

			return proxys
			
		# Prepare WHERE statment
		current_proxys = []
		current_operator = ""

		for prop in self.members:
			if position % 2.0 == 0:
				if prop[0] == "TEST_VALUE":	
					res = self._test_value_regexp.match(prop[1])
					if res:
						sql = "SELECT proxys.idproxy " + \
							"FROM proxys " + \
							"INNER JOIN proxy_property ON proxys.idproxy = proxy_property.idc_proxy " + \
							"INNER JOIN properties ON proxy_property.idc_property = properties.idproperty " + \
							"WHERE proxys.active=1 and properties.property = '" + res.group('property') + "' " + \
							"AND proxy_property.value " + res.group('operator') + " '" + res.group('value').replace('\'','').replace('"','') + "'"
						res = self.db.execute(sql)
						new_test = []
						for p in res:
							new_test.append(p['idproxy'])
						
						if position == 0:
							current_proxys = new_test
						else:
							current_proxys = self._apply_operator(current_operator, current_proxys, new_test)
					else:
						print "Invalid test value: " + prop[1]

					position = position + 1
				else:
					max_position = max_position - 1
			else:
				if position != max_position:
					if prop[0] == "OPERATOR":
						current_operator = prop[1]

					position = position + 1
				else:
					max_position = max_position - 1
		proxys = []
		for proxyid in current_proxys:
			proxys.append(Proxy(proxyid))

		return proxys


	def _apply_operator(self, operator, old, new):
		result = []
		if operator == "AND":
			# Get values presents in old and new at same time
			for p in old:
				if new.__contains__(p):
					result.append(p)
			return result	

		if operator == "OR":
			# Values in old and new without duplicates
			result = old
			for p in new:
				if not result.__contains__(p):
					result.append(p)

			return result

		if operator == "AND NOT":
			# Values in old minus values in new
			result = old
			for p in new:
				if result.__contains__(p):
					result.remove(p)

			return result
			
		# Unknown operator	
		return old

	def get_proxy(self):
		if self.proxys.__len__() > 0:
			# Lower latency
			if self.order == "lower_latency":
				first = True
				lower_proxy = self.proxys[0]
				for p in self.proxys:
					a = p.get_property("latency-totaltime")
					if a:
						if first:
							lower_latency = float(a)
							lower_proxy = p
							first = False
						else:
							a = float(a)
							if a < lower_latency:
								lower_latency = a
								lower_proxy = p	
				self.last_selected = lower_proxy
				return lower_proxy

			# Last checked
			if self.order == "last_checked":
				first = True
				for p in self.proxys:
					a = p.get_property("checked")
					if a:
						if first:
							last_checked = float(a)
							proxy = p
							first = False
						else:
							a = float(a)
							if a < last_checked:
								proxy = p	
				self.last_selected = proxy 
				return proxy 

			# Round robin
			if self.order == "round_robin":
				next = False
				if self.last_selected:
					proxy = False
					for p in self.proxys:
						if next:
							proxy = p
							break
						a = p.get_property("id")
						if self.last_selected.get_property("id") == a:
							next = True	
					if not proxy:
						self.last_selected = self.proxys[0]
						return self.proxys[0]

					self.last_selected = proxy
					return proxy
				else:
					self.last_selected = self.proxys[0]
					return self.proxys[0]

			if self.order == "random":
				return self.proxys[random.randrange(0,self.proxys.__len__())]
			if self.order == "major_order_value":
				pass
			if self.order == "minor_order_value":
				pass

if __name__ == '__main__':
	from sys import argv
	if argv[1] and argv[1]:
		print argv[0], "[port [allowed_client_name ...]]"
	else:
		if argv[2:]:
			allowed = []
			for name in argv[2:]:
				client = socket.gethostbyname(name)
				allowed.append(client)
				print "Accept: %s (%s)" % (client, name)
			ProxyHandler.allowed_clients = allowed
			del argv[2:]
		else:
			BaseHTTPServer.test(ProxyHandler, ThreadingHTTPServer)

